package com.autonavi.yunda.yunji.common.utils.geo;


import com.autonavi.yunda.yunji.common.exception.AmapException;
import com.autonavi.yunda.yunji.common.exception.AmapExceptionCode;
import lombok.extern.slf4j.Slf4j;
import org.locationtech.jts.geom.*;
import org.locationtech.jts.io.WKBReader;
import org.locationtech.jts.io.WKBWriter;
import org.locationtech.jts.io.WKTReader;
import org.locationtech.jts.io.WKTWriter;
import org.wololo.geojson.GeoJSON;
import org.wololo.jts2geojson.GeoJSONReader;
import org.wololo.jts2geojson.GeoJSONWriter;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;

/**
 * @author cizhong.wcs
 * @date 2023/5/30 17:27
 */
@Slf4j
public class GeoUtil {
    private static GeometryFactory geometryFactory = new GeometryFactory(new PrecisionModel(), 4326);

    private static WKTReader wktReader = new WKTReader(geometryFactory);

    private static WKTWriter wktWriter = new WKTWriter();

    private static WKBReader wkbReader = new WKBReader(geometryFactory);

    private static WKBWriter wkbWriter = new WKBWriter();

    /**
     * SIRD:4326
     */
    public static GeometryFactory getFactory() {
        if (geometryFactory == null) {
            geometryFactory = new GeometryFactory(new PrecisionModel(), 4326);
        }
        return geometryFactory;
    }

    public static GeometryFactory getFactory(int srid) {
        return new GeometryFactory(new PrecisionModel(), srid);
    }

    public static WKTReader getWktReader() {
        if (wktReader == null) {
            wktReader = new WKTReader(getFactory());
        }
        return wktReader;
    }

    public static WKTWriter getWktWriter() {
        if (wktWriter == null) {
            wktWriter = new WKTWriter();
        }
        return wktWriter;
    }

    public static WKBReader getWkbReader() {
        if (wkbReader == null) {
            wkbReader = new WKBReader(getFactory());
        }
        return wkbReader;
    }

    public static WKBWriter getWkbWriter() {
        if (wkbWriter == null) {
            wkbWriter = new WKBWriter();
        }
        return wkbWriter;
    }

    public static Polygon getExtent(String coords) {
        String[] split = coords.split(",");
        double minX = Double.parseDouble(split[0]);
        double minY = Double.parseDouble(split[1]);
        double maxX = Double.parseDouble(split[2]);
        double maxY = Double.parseDouble(split[3]);
        Coordinate[] coordinates = new Coordinate[5];
        coordinates[0] = new Coordinate(minX, minY);
        coordinates[1] = new Coordinate(minX, maxY);
        coordinates[2] = new Coordinate(maxX, maxY);
        coordinates[3] = new Coordinate(maxX, minY);
        coordinates[4] = new Coordinate(minX, minY);
        return getFactory().createPolygon(coordinates);
    }

    public static Point getPoint(String coords) {
        String[] split = coords.split(",");
        double x = Double.parseDouble(split[0]);
        double y = Double.parseDouble(split[1]);
        return getFactory().createPoint(new Coordinate(x, y));
    }

    /**
     * byte[] 转 geometry
     */
    public static Geometry fromMysqlWkb(byte[] bytes) {
        if (bytes == null) {
            return null;
        }
        try {
            ByteBuffer sridBuffer = ByteBuffer.allocate(4).order(ByteOrder.LITTLE_ENDIAN).put(bytes, 0, 4);
            sridBuffer.position(0);
            int srid = sridBuffer.getInt();
            byte[] geomBytes = ByteBuffer.allocate(bytes.length - 4).order(ByteOrder.LITTLE_ENDIAN)
                    .put(bytes, 4, bytes.length - 4).array();
            if (GeoUtil.getFactory().getSRID() != srid) {
                return new WKBReader(GeoUtil.getFactory(srid)).read(geomBytes);
            }
            return GeoUtil.getWkbReader().read(geomBytes);
        } catch (Exception e) {
            log.error("fromMysqlWkb error", e);
        }
        return null;
    }

    public static GeoJSON wktToGeoJSON(String wkt) {
        try {
            //String转Geometry
            Geometry geo = new WKTReader(geometryFactory).read(wkt);
            if (geo != null) {
                GeoJSONWriter writer = new GeoJSONWriter();
                return writer.write(geo);
            }
        } catch (Exception e) {
            log.error("GeoUtil wktToGeoJSON error,wkt:{}", wkt, e);
            throw new AmapException(AmapExceptionCode.COMMON_ILLEGAL_PARAM, "wkt to geo json error", e);
        }
        return null;
    }

    public static String geoJSONtoWkt(GeoJSON geoJSON) {
        GeoJSONReader reader = new GeoJSONReader();
        Geometry geo = reader.read(geoJSON);
        return geo.toString();
    }
}